package com.engine4cloud.tdf.common.core.util.preview;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import com.engine4cloud.tdf.common.core.constant.SupervisionBusinessConstants;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;


/**
 * @author 刘师兄
 * @date 2019/11/6 11:31
 */
@Slf4j
public class PreviewUtils {

    /**
     * @param data           传入的实体类
     * @param templateStream 模版流
     * @param fontStream     字体流
     * @param image          图片流（支持传入图片）
     * @param <T>            实体泛型
     * @return <T extends PreviewResultDTO> ByteArrayOutputStream
     */
    public static <T extends PreviewResultBase> ByteArrayOutputStream preview(T data, InputStream templateStream, InputStream fontStream, ImgPreviewModel image) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            // pdf模板所在路径，就是网站制作好后下载的pdf模板路径
            PdfReader reader = new PdfReader(templateStream);

            PdfStamper ps = new PdfStamper(reader, bos);
            // 使用中文字体
            BaseFont bf = BaseFont.createFont(SupervisionBusinessConstants.TEMPLATE_FONT_TTF_NAME, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, true, fontStream.readAllBytes(), null);

            ArrayList<BaseFont> fontList = new ArrayList<>();
            fontList.add(bf);
            AcroFields fields = ps.getAcroFields();
            fields.setSubstitutionFonts(fontList);

            renderData(fields, data);
            renderImage(ps, image);
            //这个配置是防止生成的pdf还能编辑，经测试，这里属性设置为true时会不显示结果
            ps.setFormFlattening(true);
            ps.close();
            bos.close();
            return bos;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return bos;
    }

    /**
     * @param data
     * @param templateBytes
     * @param fontBytes
     * @param image
     * @return
     */
    public static <T extends PreviewResultBase> ByteArrayOutputStream preview(T data, byte[] templateBytes, byte[] fontBytes, ImgPreviewModel image) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            // pdf模板所在路径，就是网站制作好后下载的pdf模板路径
            PdfReader reader = new PdfReader(templateBytes);

            PdfStamper ps = new PdfStamper(reader, bos);
            // 使用中文字体
            BaseFont bf = BaseFont.createFont(SupervisionBusinessConstants.TEMPLATE_FONT_TTF_NAME, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, true, fontBytes, null);

            ArrayList<BaseFont> fontList = new ArrayList<>();
            fontList.add(bf);
            AcroFields fields = ps.getAcroFields();
            fields.setSubstitutionFonts(fontList);

            renderData(fields, data);
            renderImage(ps, image);
            //这个配置是防止生成的pdf还能编辑，经测试，这里属性设置为true时会不显示结果
            ps.setFormFlattening(true);
            ps.close();
            bos.close();
            return bos;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return bos;
    }

    public static <T extends PreviewResultBase> void renderData(AcroFields fields, T data) {

        Class<?> dataClass = data.getClass();
        Field[] fieldList = dataClass.getDeclaredFields();
        Map<String, Object> fieldMap = new HashMap<>();

        // 遍历每个字段
        for (Field field : fieldList) {
            // 设置字段可访问
            field.setAccessible(true);
            try {
                Object obj = field.get(data);
                String name = field.getName();
                if (String.class.equals(field.getType())) {
                    fieldMap.put(name, obj);
                    log.info(name + ": " + field.get(data));
                } else if (List.class.equals(field.getType())) {
                    if (obj instanceof List list) {
                        for (int i = 0; i < list.size(); i++) {
                            Object item = list.get(i);
                            Map<String, Object> dataMap = new HashMap<>();
                            if (!(item instanceof Map)) {
                                dataMap.putAll(BeanUtil.beanToMap(item));
                            } else {
                                dataMap.putAll((Map) item);
                            }
                            for (String c : dataMap.keySet()) {
                                Object o = dataMap.get(c);
                                String itemName = name + "-r" + (i + 1) + "-" + c;
                                fieldMap.put(itemName, o);
                                log.info(itemName + ": " + o);
                            }
                        }
                    }
                } else {
                    log.error("不支持当前数据类型" + field.getType().getTypeName());
                }

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        if (MapUtil.isNotEmpty(fieldMap)) {
            renderData(fields, fieldMap);
        }
    }

    /**
     * 填充模板中的数据
     */
    public static void renderData(AcroFields fields, Map<String, Object> data) {
        try {

            Map<String, AcroFields.Item> itemMap = fields.getFields();
            for (String key : itemMap.keySet()) {
                if (data.containsKey(key)) {
                    String value = Objects.isNull(data.get(key)) ? "" : String.valueOf(data.get(key));
                    // 为字段赋值,注意字段名称是区分大小写的
                    fields.setFieldProperty(key, SupervisionBusinessConstants.TEMPLATE_FONT_TEXT_SIZE, 10f, null);
                    fields.setField(key, value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 填充图片（这里还需要再测试一下）
     *
     * @param ps    PdfStamper
     * @param image 图片对象
     * @throws DocumentException IOException 异常
     */
    public static void renderImage(PdfStamper ps, ImgPreviewModel image) throws DocumentException, IOException {
        if (Objects.nonNull(image) && image.getImageBytes() != null && image.getX() > 0 && image.getY() > 0) {
            Image img = Image.getInstance(image.getImageBytes());
            img.setAbsolutePosition(image.getX(), image.getY());
            // 指定图片的宽高
            img.scaleAbsolute(image.getWidth(), image.getHeight());
            // 添加图片到指定页面， 1表示第一页
            PdfContentByte content = ps.getOverContent(1);
            content.addImage(img);
        }
    }
}
